﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Collections;

namespace LSFireWall
{
    public class TcpTableView
    {

        //GetTcpTable APIのインポート
        [DllImport("iphlpapi.dll", CharSet = CharSet.Auto)]
        public extern static int GetTcpTable(IntPtr pTcpTable,
                                             ref int pdwSize, bool bOrder
                                            );

        //GetTcpTable の戻り値
        public const short NO_ERROR = 0;
        public const short ERROR_NOT_SUPPORTED = 50;
        public const short ERROR_INVALID_PARAMETER = 87;
        public const short ERROR_INSUFFICIENT_BUFFER = 112;

        /*MIB_TCPTABLE 構造体
        [ StructLayout(LayoutKind.Sequential) ]
        public struct MIB_TCPTABLE{
          public int dwNumEntries;
          public MIB_TCPROW[] table;
        }
        */

        //MIB_TCPROW 構造体
        [StructLayout(LayoutKind.Sequential)]
        public struct MIB_TCPROW
        {
            public int dwState;
            public int dwLocalAddr;
            public int dwLocalPort;
            public int dwRemoteAddr;
            public int dwRemotePort;
        }

        //MIB_TCPROW.dwState 用定義
        public const short MIB_TCP_STATE_CLOSED = 1;
        public const short MIB_TCP_STATE_LISTEN = 2;
        public const short MIB_TCP_STATE_SYN_SENT = 3;
        public const short MIB_TCP_STATE_SYN_RCVD = 4;
        public const short MIB_TCP_STATE_ESTAB = 5;
        public const short MIB_TCP_STATE_FIN_WAIT1 = 6;
        public const short MIB_TCP_STATE_FIN_WAIT2 = 7;
        public const short MIB_TCP_STATE_CLOSE_WAIT = 8;
        public const short MIB_TCP_STATE_CLOSING = 9;
        public const short MIB_TCP_STATE_LAST_ACK = 10;
        public const short MIB_TCP_STATE_TIME_WAIT = 11;
        public const short MIB_TCP_STATE_DELETE_TCB = 12;

        public static string[] StateStrings = {"", "CLOSED","LISTEN","SYN_SENT","SYN_RCVD","ESTABLISHED","FIN_WAIT1","FIN_WAIT2",
                                           "CLOSE_WAIT","CLOSING","LAST_ACK","TIME_WAIT","DELETE_TCB"};


        //============================================================


        //public static void Main()
        //{
        //    ArrayList TcpTable = GetTcpTableView();

        //    //結果を表示
        //    for (int i = 0; i <= TcpTable.Count - 1; i++)
        //    {
        //        Console.Write(GetIpAddress(((TcpRow)TcpTable[i]).LocalAddr));
        //        Console.Write(" ");
        //        Console.Write(GetPortNumber(((TcpRow)TcpTable[i]).LocalPort));
        //        Console.Write(" ");
        //        Console.Write(GetIpAddress(((TcpRow)TcpTable[i]).RemoteAddr));
        //        Console.Write(" ");
        //        Console.Write(GetPortNumber(((TcpRow)TcpTable[i]).RemotePort));
        //        Console.Write(" ");
        //        Console.Write(StateStrings[((TcpRow)TcpTable[i]).State]);
        //        Console.WriteLine("");
        //    }
        //}

        public static ArrayList GetTcpTableView()
        {
            int pdwSize = 0;
            IntPtr pTcpTable = IntPtr.Zero;  //TcpTable用ポインタ
            GetTcpTable(pTcpTable, ref pdwSize, false);  //pdwSizeを取得
            pTcpTable = Marshal.AllocHGlobal(pdwSize);   //メモリを割り当て

            try
            {
                //TCPの一覧を取得
                if (GetTcpTable(pTcpTable, ref pdwSize, true) == NO_ERROR)
                {
                    int RowCount = Marshal.ReadInt32(pTcpTable);  //MIB_TCPTABLE.dwNumEntriesを読み取り

                    ArrayList TcpTable = new ArrayList();  //結果用リスト

                    for (int i = 0; i <= RowCount - 1; i++)
                    {
                        //1列ずつ取得
                        IntPtr pTcpRow = new IntPtr(pTcpTable.ToInt32() + 4 + (i * Marshal.SizeOf(typeof(MIB_TCPROW))));
                        MIB_TCPROW _TcpRow = new MIB_TCPROW();
                        _TcpRow = (MIB_TCPROW)Marshal.PtrToStructure(pTcpRow, typeof(MIB_TCPROW));

                        //取得結果
                        TcpRow row = new TcpRow();
                        row.LocalAddr = _TcpRow.dwLocalAddr;
                        row.LocalPort = _TcpRow.dwLocalPort;
                        row.RemoteAddr = _TcpRow.dwRemoteAddr;
                        row.RemotePort = _TcpRow.dwRemotePort;
                        row.State = _TcpRow.dwState;
                        //RemoteAddrが0の場合は、Remoteポートも0にする
                        if (row.RemoteAddr == 0) row.RemotePort = 0;

                        TcpTable.Add(row);
                    }  //for

                    return TcpTable;

                }  //if
                else
                    return null;

            }  //try
            finally
            {
                Marshal.FreeHGlobal(pTcpTable);  //メモリ開放
            }

        } //gettcptableview


        private static string GetIpAddress(int Address)
        {
            byte[] IpParts = BitConverter.GetBytes(Address);

            StringBuilder builder = new StringBuilder();
            builder.Append(IpParts[0].ToString());
            builder.Append(".");
            builder.Append(IpParts[1].ToString());
            builder.Append(".");
            builder.Append(IpParts[2].ToString());
            builder.Append(".");
            builder.Append(IpParts[3].ToString());

            return builder.ToString();
        }

        private static int GetPortNumber(int Port)
        {
            return Port / 256 + (Port % 256) * 256;
        }

    } //class


    public struct TcpRow
    {
        public int LocalAddr;
        public int LocalPort;
        public int RemoteAddr;
        public int RemotePort;
        public int State;
    }


}
